package org.ehe.erp.service.quality.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ehe.business.bom.domain.BomMaster;
import org.ehe.business.bom.service.BomMasterService;
import org.ehe.business.monitor.MonitorMethod;
import org.ehe.business.overdue.config.OverdueStatus;
import org.ehe.business.overdue.extract.FeedBackDataExtractor;
import org.ehe.business.overdue.extract.QualityDataExtractor;
import org.ehe.business.timeout.contants.BizTypeConstant;
import org.ehe.business.timeout.domain.SsePushMessage;
import org.ehe.business.timeout.mapper.SsePushMessageMapper;
import org.ehe.common.core.constant.StatusEnum;
import org.ehe.common.core.domain.dto.StartProcessDTO;
import org.ehe.common.core.domain.dto.StartProcessReturnDTO;
import org.ehe.common.core.service.WorkflowService;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.common.sse.dto.SseMessageDto;
import org.ehe.common.sse.utils.SseMessageUtils;
import org.ehe.erp.domain.product.bo.ErpProductBo;
import org.ehe.erp.domain.product.vo.ErpProductVo;
import org.ehe.erp.domain.quality.ErpQualityFeedback;
import org.ehe.erp.domain.quality.ErpQualityTask;
import org.ehe.erp.domain.quality.bo.ErpQualityFeedbackBo;
import org.ehe.erp.domain.quality.dto.QualityFeedbackQueryDto;
import org.ehe.erp.domain.quality.vo.ErpQualityAttachmentVo;
import org.ehe.erp.domain.quality.vo.ErpQualityFeedbackVo;
import org.ehe.erp.domain.quality.vo.ErpQualityRecordVo;
import org.ehe.erp.enums.ErpAuditStatus;
import org.ehe.erp.mapper.quality.ErpQualityFeedbackMapper;
import org.ehe.erp.mapper.quality.ErpQualityRecordMapper;
import org.ehe.erp.mapper.quality.ErpQualityTaskMapper;
import org.ehe.erp.service.product.IErpProductService;
import org.ehe.erp.service.quality.ErpQualityAttachmentService;
import org.ehe.erp.service.quality.ErpQualityFeedbackService;
import org.ehe.system.domain.vo.SysUserVo;
import org.ehe.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class ErpQualityFeedbackServiceImpl extends ServiceImpl<ErpQualityFeedbackMapper, ErpQualityFeedback>
    implements ErpQualityFeedbackService {

    private final ErpQualityFeedbackMapper baseMapper;
    private final ISysUserService userService;
    private final ScheduledExecutorService scheduledExecutorService;
    private final SsePushMessageMapper ssePushMessageMapper;
    private final ErpQualityAttachmentService qualityAttachmentService;
    private final BomMasterService bomMasterService;
    private final ErpQualityTaskMapper qualityTaskMapper;
    private final ErpQualityRecordMapper qualityRecordMapper;
    private final IErpProductService productService;
    private final ErpQualityAttachmentService attachmentService;
    private final WorkflowService workflowService;

    /**
     * 分页查询异常反馈列表
     *
     * @param dto       查询条件
     * @param pageQuery 分页参数
     * @return
     */
    @Override
    public TableDataInfo<ErpQualityFeedbackVo> queryPageList(QualityFeedbackQueryDto dto, PageQuery pageQuery) {
        LambdaQueryWrapper<ErpQualityFeedback> wrapper = buildWrapper(dto);
        IPage<ErpQualityFeedbackVo> page = baseMapper.selectVoPage(pageQuery.build(), wrapper);
        queryDetailInfo(pageQuery, page.getRecords());
        return TableDataInfo.build(page);
    }

    /**
     * 不分页查询异常反馈列表
     *
     * @param dto 查询条件
     * @return
     */
    @Override
    public List<ErpQualityFeedbackVo> queryList(QualityFeedbackQueryDto dto) {
        List<ErpQualityFeedbackVo> erpQualityFeedbackVos = baseMapper.selectVoList(buildWrapper(dto));
        queryDetailInfo(new PageQuery(1,10),erpQualityFeedbackVos);
        return erpQualityFeedbackVos;
    }

    private void queryDetailInfo(PageQuery pageQuery, List<ErpQualityFeedbackVo> qualityFeedbackVos) {
        qualityFeedbackVos.forEach(p -> {
            //bom
            Long taskId = p.getTaskId();
            ErpQualityTask task = qualityTaskMapper.selectById(taskId);
            if (Objects.nonNull(task)) {
                p.setTaskNo(task.getTaskNo());
                BomMaster bomMaster = bomMasterService.getById(task.getBomId());
                if (Objects.nonNull(bomMaster)) {
                    p.setBomCode(bomMaster.getBomCode());
                    p.setBomName(bomMaster.getBomName());
                }
            }
            //产品
            Long recordId = p.getRecordId();
            ErpQualityRecordVo qualityRecord = qualityRecordMapper.selectVoById(recordId);
            if (Objects.nonNull(qualityRecord)) {
                Long productId = qualityRecord.getProductId();
                ErpProductBo productBo = new ErpProductBo();
                productBo.setId(productId);
                TableDataInfo<ErpProductVo> erpProductVoTableDataInfo = productService.queryPageList(productBo, pageQuery);
                p.setProductVo(erpProductVoTableDataInfo.getRows().get(0));
            }
            String feedbackPerson = p.getFeedbackPerson();
            SysUserVo sysUserVo = userService.selectUserByUserName(feedbackPerson);
            if (Objects.nonNull(sysUserVo)) {
                p.setFeedbackPerson(sysUserVo.getNickName());
            }
            if (StringUtils.isNotBlank(p.getHandlerName())) {
                sysUserVo = userService.selectUserById(p.getHandlerId());
                if (Objects.nonNull(sysUserVo)) {
                    p.setHandlerName(sysUserVo.getNickName());
                }
            }
            //反馈附件信息
            List<ErpQualityAttachmentVo> attachmentVoList = attachmentService.listByFeedbackId(p.getId());
            p.setAttachmentVoList(attachmentVoList);



        });
    }


    /**
     * 获取详细信息
     * @param id 主键
     * @return
     */
    @Override
    public ErpQualityFeedbackVo queryById(Long id) {
        ErpQualityFeedbackVo erpQualityFeedbackVo = baseMapper.selectVoById(id);
        if(Objects.nonNull(erpQualityFeedbackVo)){
            Long recordId = erpQualityFeedbackVo.getRecordId();
            ErpQualityRecordVo qualityRecordVo = qualityRecordMapper.selectVoById(recordId);
            if(Objects.nonNull(qualityRecordVo)){
                ErpProductVo erpProductVo = productService.queryById(qualityRecordVo.getProductId());
                erpQualityFeedbackVo.setProductName(erpProductVo.getName());
            }
        }
        return erpQualityFeedbackVo;
    }


    /**
     * 新增
     * 自动发起异常流程
     * @param bo 业务对象
     * @return
     */
    @Override
    //@MonitorMethod(bizType = BizTypeConstant.FEEDBACK+"Overdue", extractor = FeedBackDataExtractor.class)
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(ErpQualityFeedbackBo bo) {
        // 1. 校验单号唯一
        if (StrUtil.isNotBlank(bo.getFeedbackNo()) && !checkFeedbackNoUnique(bo.getFeedbackNo(), null)) {
            throw new RuntimeException("反馈单号已存在");
        }
        // 2. 自动生成单号
        if (StrUtil.isBlank(bo.getFeedbackNo())) {
            bo.setFeedbackNo(generateFeedbackNo());
        }
        // 3. 填充默认字段
        if (bo.getFeedbackTime() == null) {
            bo.setFeedbackTime(LocalDateTime.now());
        }
        if (bo.getStatus() == null) {
            bo.setStatus(0); // 待处理
        }
        if (bo.getSeverityLevel() == null) {
            bo.setSeverityLevel(1); // 一般
        }
        //质检
        bo.setRecordType("quality");
        //提交
        bo.setApproveStatus(ErpAuditStatus.SUBMITTED.getStatus().toString());
        //bo.setIsOverdue(OverdueStatus.PENDING);
        // 4. 保存
        ErpQualityFeedback entity = BeanUtil.toBean(bo, ErpQualityFeedback.class);
        this.baseMapper.insert(entity);
        Long feedbackId = entity.getId();
        bo.setId(feedbackId);

        /* 5. 保存附件 */
        if (CollUtil.isNotEmpty(bo.getAttachmentBoList())) {
            String loginUser = LoginHelper.getUsername();
            bo.getAttachmentBoList().forEach(a -> {
                a.setFeedbackId(feedbackId);
                a.setTaskId(entity.getTaskId());
                a.setRecordId(entity.getRecordId());
                a.setUploadPerson(loginUser);
                a.setUploadTime(LocalDateTime.now());
            });
            qualityAttachmentService.saveBatch(bo.getAttachmentBoList());
        }

        handleFeedback(feedbackId, 0, "质检新增反馈，待处理");

        //发起工作流
        StartProcessDTO process = new StartProcessDTO();
        Map<String,Object> map = new HashMap<>();
        map.put("type","feedback");
        process.setVariables(map);
        //BOM 完成审批流程
        process.setFlowCode("feedback");
        process.setBusinessId(String.valueOf(bo.getId()));
        StartProcessReturnDTO processReturnDTO = workflowService.startWorkFlow(process);
        log.info("流程审批发起成功，已启动: feedback={}, engineerId={}", bo.getId(), bo.getCreateBy());
        ErpQualityFeedbackVo erpQualityFeedbackVo = this.queryById(feedbackId);
        String productName = "";
        if(Objects.nonNull(erpQualityFeedbackVo)){
            productName = erpQualityFeedbackVo.getProductName();
        }

        workflowService.completeTask(processReturnDTO.getTaskId(),"原因:"+productName+":"+entity.getProblemDesc());

        return true;
    }

    /**
     * 修改
     *
     * @param bo 业务对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(ErpQualityFeedbackBo bo) {
        if (StrUtil.isNotBlank(bo.getFeedbackNo()) && !checkFeedbackNoUnique(bo.getFeedbackNo(), bo.getId())) {
            throw new RuntimeException("反馈单号已存在");
        }
        ErpQualityFeedback entity = BeanUtil.toBean(bo, ErpQualityFeedback.class);
        return baseMapper.updateById(entity) > 0;
    }

    /**
     * 删除
     *
     * @param ids     主键集合
     * @param isValid 是否做业务校验
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 可扩展：是否允许删除已关闭/已处理单据
            long closed = lambdaQuery().in(ErpQualityFeedback::getId, ids)
                .eq(ErpQualityFeedback::getStatus, 3).count();
            if (closed > 0) {
                throw new RuntimeException("已关闭的反馈不允许删除");
            }
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 提交质检记录
     * @param id
     * @return
     */
    @Override
    public ErpQualityFeedback submit(Long id,Long handlerId) {
        ErpQualityFeedback feedback = this.baseMapper.selectById(id);

        if(null != feedback.getIsOverdueEndTime() && feedback.getIsOverdueEndTime().isBefore(LocalDateTime.now())){
            feedback.setIsOverdue(OverdueStatus.OVERDUE_AND_PROCESSED);
        }
        //已经提交
        feedback.setHandlerId(handlerId);
        feedback.setApproveStatus(ErpAuditStatus.PENDING_SUBMIT.getStatus().toString());
        feedback.setStatus(Integer.valueOf(StatusEnum.CLZ.getCode())); //待处理
        feedback.setEstimatedHours(1); //质检要求1h之内
        feedback.setTaskDeadline(LocalDateTime.now().plusHours(1));
        feedback.setIsOverdue(OverdueStatus.PENDING);
        feedback.setIsOverdueEndTime(LocalDateTime.now().plusHours(1));
        this.baseMapper.updateById(feedback);

        return feedback;
    }

    /**
     * 状态流转
     *
     * @param id           主键
     * @param targetStatus 目标状态
     * @param handleResult 处理结果（必填）
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ErpQualityFeedback handleFeedback(Long id, Integer targetStatus, String handleResult) {
        ErpQualityFeedback feedback = baseMapper.selectById(id);
        if (feedback == null) {
            throw new RuntimeException("异常反馈不存在");
        }
        // 已处理/已关闭必须填写处理结果
        if ((targetStatus == 4 || targetStatus == 3) && StrUtil.isBlank(handleResult)) {
            throw new RuntimeException("处理结果不能为空");
        }
        feedback.setApproveStatus(ErpAuditStatus.SUBMITTED.getStatus().toString());
        // 填充处理人与时间
        LambdaUpdateWrapper<ErpQualityFeedback> wrapper = Wrappers.<ErpQualityFeedback>lambdaUpdate()
            .eq(ErpQualityFeedback::getId, id)
            .set(ErpQualityFeedback::getStatus, targetStatus)
            .set(ErpQualityFeedback::getHandleResult, handleResult);
        if (targetStatus >= 2) {
            wrapper.set(ErpQualityFeedback::getHandlerId, LoginHelper.getUserId())
                .set(ErpQualityFeedback::getHandlerName, LoginHelper.getUsername())
                .set(ErpQualityFeedback::getHandleTime, LocalDateTime.now());
        }
        update(wrapper);
        return feedback;
    }

    /**
     * 唯一性校验
     *
     * @param feedbackNo 单号
     * @param id         排除的主键（null 表示新增）
     * @return
     */
    @Override
    public Boolean checkFeedbackNoUnique(String feedbackNo, Long id) {
        LambdaQueryWrapper<ErpQualityFeedback> wrapper = Wrappers.<ErpQualityFeedback>lambdaQuery()
            .eq(ErpQualityFeedback::getFeedbackNo, feedbackNo);
        if (ObjectUtil.isNotNull(id)) {
            wrapper.ne(ErpQualityFeedback::getId, id);
        }
        return baseMapper.selectCount(wrapper) == 0;
    }

    /**
     * 查询条件
     *
     * @param dto
     * @return
     */
    private LambdaQueryWrapper<ErpQualityFeedback> buildWrapper(QualityFeedbackQueryDto dto) {
        LambdaQueryWrapper<ErpQualityFeedback> w = Wrappers.lambdaQuery();
        w.like(StrUtil.isNotBlank(dto.getFeedbackNo()), ErpQualityFeedback::getFeedbackNo, dto.getFeedbackNo());
        w.eq(ObjectUtil.isNotNull(dto.getTaskId()), ErpQualityFeedback::getTaskId, dto.getTaskId());
        w.eq(ObjectUtil.isNotNull(dto.getFeedbackType()), ErpQualityFeedback::getFeedbackType, dto.getFeedbackType());
        w.eq(ObjectUtil.isNotNull(dto.getSeverityLevel()), ErpQualityFeedback::getSeverityLevel, dto.getSeverityLevel());
        w.eq(ObjectUtil.isNotNull(dto.getStatus()), ErpQualityFeedback::getStatus, dto.getStatus());
        w.like(StrUtil.isNotBlank(dto.getFeedbackPerson()), ErpQualityFeedback::getFeedbackPerson, dto.getFeedbackPerson());
        w.like(StrUtil.isNotBlank(dto.getHandlerName()), ErpQualityFeedback::getHandlerName, dto.getHandlerName());
        w.eq(ObjectUtil.isNotNull(dto.getSuspectedSupplierId()), ErpQualityFeedback::getSuspectedSupplierId, dto.getSuspectedSupplierId());
        w.eq(ObjectUtil.isNotNull(dto.getSuspectedMaterialId()), ErpQualityFeedback::getSuspectedMaterialId, dto.getSuspectedMaterialId());
        if (dto.getFeedbackTimeStart() != null) {
            w.ge(ErpQualityFeedback::getFeedbackTime, dto.getFeedbackTimeStart());
        }
        if (dto.getFeedbackTimeEnd() != null) {
            w.le(ErpQualityFeedback::getFeedbackTime, dto.getFeedbackTimeEnd());
        }
        w.orderByDesc(ErpQualityFeedback::getCreateTime);
        return w;
    }

    /**
     * 单号生成
     *
     * @return
     */
    public String generateFeedbackNo() {
        String date = DateUtil.format(LocalDateTime.now(), "yyyyMMdd");
        String prefix = "QF" + date;
        String maxNo = lambdaQuery()
            .likeRight(ErpQualityFeedback::getFeedbackNo, prefix)
            .orderByDesc(ErpQualityFeedback::getFeedbackNo)
            .last("limit 1")
            .oneOpt()
            .map(ErpQualityFeedback::getFeedbackNo)
            .orElse(prefix + "000");
        int seq = Integer.parseInt(maxNo.substring(prefix.length())) + 1;
        return prefix + String.format("%03d", seq);
    }

    /**
     * 推送反馈消息
     *
     * @param feedbackId
     * @param content
     */
    private void pushFeedbackMessage(Long feedbackId, String content) {
        /* 1. 查询需要接收的用户 */
        List<Long> userIds = CollUtil.newArrayList();

        ErpQualityFeedback fb = getById(feedbackId);
        if (fb.getHandlerId() != null) userIds.add(fb.getHandlerId());
        if (StrUtil.isNotBlank(fb.getFeedbackPerson())) {
            // 根据姓名反查
            SysUserVo sysUserVo = userService.selectUserByUserName(fb.getFeedbackPerson());
            if (sysUserVo != null) userIds.add(sysUserVo.getUserId());
        }

        if (CollUtil.isEmpty(userIds)) return;

        /* 2. 组装 DTO */
        SseMessageDto dto = new SseMessageDto();
        dto.setMessage(content);
        dto.setUserIds(userIds);
        dto.setMessageType("QUALITY_FEEDBACK");
        /* 3. 入库 */
        SsePushMessage push = new SsePushMessage();
        push.setInstanceId(null);
        push.setMessage(content);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < userIds.size(); i++) {
            sb.append(userIds.get(i));
            // 最后一个元素后不添加逗号
            if (i != userIds.size() - 1) {
                sb.append(",");
            }
        }
        push.setUserIds(sb.toString());
        push.setMessageType("QUALITY_FEEDBACK");
        ssePushMessageMapper.insert(push);

        /* 4. 推送 */
        SseMessageUtils.publishMessage(dto);
    }
}
